package com.gxitsky.service.impl;

import com.alibaba.fastjson.JSON;
import com.gxitsky.common.utils.WebServiceExecutor;
import com.gxitsky.entity.ServiceRequest;
import com.gxitsky.service.IService;
import org.apache.commons.io.output.ByteArrayOutputStream;
import org.apache.cxf.endpoint.Client;
import org.apache.cxf.jaxws.endpoint.dynamic.JaxWsDynamicClientFactory;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import org.springframework.util.ObjectUtils;

import javax.xml.namespace.QName;
import javax.xml.soap.*;
import java.io.IOException;
import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * @author gxing
 * @desc 调用 WebService
 * @date 2021/2/26
 */
@Service
public class ServiceImpl implements IService {
    private static final Logger logger = LogManager.getLogger(ServiceImpl.class);

    /**
     * CXF客户端动态调用
     *
     * @param serviceRequest
     * @return
     */
    public Object cxfInvoke(ServiceRequest serviceRequest) {
        try {
            List<Object> paramList = serviceRequest.getParamList();
            Object[] params = CollectionUtils.isEmpty(paramList) ? new Object[0] : paramList.toArray();

            String wsdUrl = serviceRequest.getWsdUrl();
            String operationName = serviceRequest.getOperationName();
            //请求
            logger.info("Web Service Request, wsdUrl:{}, operationName:{}, params:{}", wsdUrl, operationName, JSON.toJSONString(params));
            String result = WebServiceExecutor.invokeRemoteMethod(wsdUrl, operationName, params)[0].toString();
            logger.info("Web Service Response:{}", result);
            return result;
        } catch (Exception e) {
            e.printStackTrace();
            throw new RuntimeException(e);
        }
    }

    /**
     * SOAP连接调Web Service接口
     *
     * @param serviceRequest
     */
    public Object soapInvoke(ServiceRequest serviceRequest) {
        String wsdUrl = serviceRequest.getWsdUrl();
        String namespaceURI = serviceRequest.getNamespaceURI();
        String operationName = serviceRequest.getOperationName();
        String prefix = serviceRequest.getPrefix();
        HashMap<String, String> paramsMap = serviceRequest.getParamsMap();

        ByteArrayOutputStream outputStream = null;
        try {
            SOAPConnectionFactory factory = SOAPConnectionFactory.newInstance();
            SOAPConnection connection = factory.createConnection();
            MessageFactory messageFactory = MessageFactory.newInstance();
            //消息体
            SOAPMessage message = messageFactory.createMessage();
            SOAPPart part = message.getSOAPPart();
            SOAPEnvelope envelope = part.getEnvelope();
            envelope.addNamespaceDeclaration(prefix, namespaceURI);

            SOAPHeader header = message.getSOAPHeader();
            header.detachNode();
            SOAPBody body = message.getSOAPBody();

            QName bodyName = new QName(namespaceURI, operationName, prefix);
            SOAPBodyElement element = body.addBodyElement(bodyName);

            // 组装请求参数
            for (Map.Entry<String, String> entry : paramsMap.entrySet()) {
                QName sub = null;
                if (serviceRequest.isQualified()) {
                    sub = new QName(namespaceURI, entry.getKey(), prefix);
                } else {
                    sub = new QName(entry.getKey());
                }
                SOAPElement childElement = element.addChildElement(sub);
                childElement.addTextNode(entry.getValue());
            }

            //请求体
            outputStream = new ByteArrayOutputStream();
            message.writeTo(outputStream);
            String requestBody = outputStream.toString(Charset.defaultCharset());
            logger.info("Web Service Request Body:{}", requestBody);

            //执行请求
            SOAPMessage result = connection.call(message, wsdUrl);
            logger.info("Request Web Service End.");
            //响应体
            outputStream.reset();
            result.writeTo(outputStream);
            String responseBody = outputStream.toString(Charset.defaultCharset());
            logger.info("Web Service Response:{}", responseBody);

            //响应文本
            org.w3c.dom.Node firstChild = result.getSOAPBody().getFirstChild();
            org.w3c.dom.Node subChild = firstChild.getFirstChild();
            String textContent = subChild.getTextContent();
            logger.info("Web Service Response textContent:{}", textContent);
            return textContent;
        } catch (SOAPException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if (!ObjectUtils.isEmpty(outputStream)) {
                try {
                    outputStream.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
        throw new RuntimeException("请求异常");
    }

//    /**
//     * 代理类工厂的方式
//     * Web Service 服务端需要提供接口的jar包供客户端引入
//     * 需要拿到对方的接口地址, 同时需要引入接口
//     */
//    public Object proxyFactoryInvoke(ServiceRequest serviceRequest) {
//        try {
//            // 接口地址
//            String address = serviceRequest.getWsdUrl();
//            // 代理工厂
//            JaxWsProxyFactoryBean jaxWsProxyFactoryBean = new JaxWsProxyFactoryBean();
//            // 设置代理地址
//            jaxWsProxyFactoryBean.setAddress(address);
//            // 设置接口类型
//            jaxWsProxyFactoryBean.setServiceClass(HelloService.class);
//            // 创建一个代理接口实现
//            HelloService us = (HelloService) jaxWsProxyFactoryBean.create();
//            // 调用代理接口的方法调用并返回结果
//            String result = (String) us.helloMessageServer("Hello", "World");
//            System.out.println(result);
//            return result;
//        } catch (Exception e) {
//            e.printStackTrace();
//        }
//        throw new RuntimeException("请求 Web Service 异常");
//    }

    /**
     * CXF客户端动态调用
     */
    @Override
    public Object cxfClientInvoke() {
        // 创建动态客户端
        JaxWsDynamicClientFactory clientFactory = JaxWsDynamicClientFactory.newInstance();
        Client client = clientFactory.createClient("http://localhost:8080/services/ws/hello?wsdl");

        // 需要密码的情况需要加上用户名和密码
        // client.getOutInterceptors().add(new ClientLoginInterceptor(USER_NAME, PASS_WORD));
        Object[] objects = new Object[0];

        List<Object> paramList = new ArrayList<>();
        paramList.add("Hello");
        paramList.add("World");

        Object[] params = paramList.toArray();

        try {
            // invoke("方法名",参数1,参数2,参数3....);
            //这里注意如果是复杂参数的话，要保证复杂参数可以序列化
            objects = client.invoke("helloMessageServer", params);
            System.out.println("Service Response:" + JSON.toJSONString(objects[0]));
        } catch (Exception e) {
            e.printStackTrace();
        }
        return objects[0];
    }
}
